package com.jacky.ocr_plugin;

import android.Manifest;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

import java.util.HashMap;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.jacky.ocr_plugin.camera.CustomOcrRectView2;
import com.jacky.util.FilePathUtils;
import com.jacky.util.OcrLogger;
import com.jacky.util.OcrUtil;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.platform.PlatformView;

/**
 * ocr识别控件
 * Created by liaoyacheng on 2021/9/13.
 */
public class OcrRectView implements PlatformView, MethodChannel.MethodCallHandler, PluginRegistry.RequestPermissionsResultListener,PluginRegistry.ActivityResultListener {

    private static final int REQUEST_TAKE = 1001;
    private final MethodChannel channel;
    private CustomOcrRectView2 ocrRectView;
    private boolean isPaused = false;
    private boolean permissionGranted;
    private boolean isTorchOn;
    private HashMap<String, Object> params;
    private final MyLifecycleCallbacks mMyLifecycleCallbacks;

    public OcrRectView(BinaryMessenger messenger, int id, HashMap<String, Object> params) {
        String name = "com.jacky.util/ocr_view_" + id;
        channel = new MethodChannel(messenger, name);
        channel.setMethodCallHandler(this);
        this.params = params;
        mMyLifecycleCallbacks = new MyLifecycleCallbacks();
        init();
    }


    @Override
    public View getView() {
        return initView();
    }

    @Override
    public void dispose() {
        if (ocrRectView != null) ocrRectView.close();
        ocrRectView = null;
        if(getActivity() != null) {
            getActivity().getApplication().unregisterActivityLifecycleCallbacks(mMyLifecycleCallbacks);
        }
    }
    
    private Activity getActivity(){
        if(Shared.currentActivity != null)return Shared.currentActivity.get();
        return null;
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        switch (call.method) {
            case "startScan":
                startScan(call,result);
                break;
            case "stopScan":
                stopScan(result);
                break;
            case "toggleFlash":
                toggleFlash(result);
                break;
            case "pauseCamera":
                pauseCamera(result);
                break;
            case "stopCamera":
                stopCamera(result);
                break;
            case "resumeCamera":
                resumeCamera(result);
                break;
            case "setDimensions":
                setDimensions(call,result);
                break;
            case "takePhotoLibrary":
                takePhotoLibrary(result);
                break;
            case "takePhotoCamera":
                takePhotoCamera(call, result);
                break;
            case "switchCamera":
                switchCamera(result);
                break;
            case "updateParams":
                updateParams(call,result);
                break;
            default:
                OcrLogger.d("ocrRectView","flutter to android,notImplemented method "+call.method);
                result.notImplemented();
                break;
        }
    }

    private void updateParams(MethodCall call, MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        params = call.arguments instanceof Map ? (HashMap<String, Object>) call.arguments : null;
        if(params != null)ocrRectView.setParams(params);
        result.success(true);
    }

    @Override
    public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == Shared.CAMERA_REQUEST_ID) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                permissionGranted = true;
                channel.invokeMethod("onPermissionSet", true);
                return true;
            } else {
                permissionGranted = false;
                channel.invokeMethod("onPermissionSet", false);
                return false;
            }
        }
        return false;
    }

    private void checkCameraOpen(){
        if(ocrRectView == null)return;
        ocrRectView.checkCameraOpen();
    }

    private CustomOcrRectView2 initView() {
        if (ocrRectView == null) {
            ocrRectView = new CustomOcrRectView2(getActivity());
        }
        ocrRectView.setParams(params);
        return ocrRectView;
    }

    private void startScan(MethodCall call, MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        checkAndRequestPermission(result);
        HashMap<String,String> map = new HashMap<>();
        ocrRectView.setOcrImgFilePath(call.argument("ocrImgPath"),call.argument("ocrHeadPath"));
        ocrRectView.setOcrRectCallback(back -> channel.invokeMethod("onOcrRecognize", back));
        ocrRectView.setOcrRectErrorCallback((code,message) -> {
            map.put("code",code);
            map.put("message",message);
            channel.invokeMethod("onOcrRectError", map);
        });
        ocrRectView.startDecoding();
    }

    private void stopScan(MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        ocrRectView.stopDecoding();
        result.success(true);
    }

    private void pauseCamera(MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        if (!isPaused) {
            isPaused = true;
            ocrRectView.pause();
        }
        result.success(true);
    }

    private void resumeCamera(MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        if (isPaused) {
            isPaused = false;
            ocrRectView.resume();
        }
        result.success(true);
    }

    private void stopCamera(MethodChannel.Result result){
        if (ocrRectView == null) {
            //ocrViewNotSet(result);
            return;
        }
        ocrRectView.close();
        result.success(true);
    }

    private void toggleFlash(MethodChannel.Result result) {
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        if (hasFlash()) {
            boolean can = ocrRectView.setTorchFlash(!isTorchOn);
            if(can)isTorchOn = !isTorchOn;
            result.success(isTorchOn);
        } else {
            result.error("404", "This device doesn't support flash", null);
        }

    }

    ///设置识别区域，没有设置则默认摄像头区域
    private void setDimensions(MethodCall call, MethodChannel.Result result) {
        Double aLeft = call.argument("areaLeft");
        Double aTop = call.argument("areaTop");
        Double aWidth = call.argument("areaWidth");
        Double aHeight = call.argument("areaHeight");
        //Boolean portraitToLandscape = call.argument("portraitToLandscape");
        OcrLogger.d("ocrRectView","flutter to android,setDimensions left "+aLeft + " top " + aTop
                + " width "+aWidth+" height "+aHeight + " hasView " + (ocrRectView != null));
        if(aLeft == null || aTop == null || aWidth == null || aHeight == null
                || aWidth <= 0 || aHeight <= 0){
            result.success(false);
            return;
        }
        Context context = getView().getContext();
        int left = OcrUtil.dip2px(context,aLeft.intValue());
        int top = OcrUtil.dip2px(context,aTop.intValue());
        int width = OcrUtil.dip2px(context,aWidth.intValue());
        int height = OcrUtil.dip2px(context,aHeight.intValue());
        Rect rect = new Rect(left,top, left + width,top + height);
        if(ocrRectView != null){
            //默认值 true
            ocrRectView.setRecognizeRect(rect);
        }
        result.success(ocrRectView != null);
    }

    private void takePhotoLibrary(MethodChannel.Result result){
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        if(getActivity() == null){
            result.error("405", "No activity found for pick photo", null);
            return;
        }
        Intent intent = new Intent(Intent.ACTION_PICK).setType("image/*");
        getActivity().startActivityForResult(intent,REQUEST_TAKE);

        result.success(true);
    }

    private void takePhotoCamera(MethodCall call,MethodChannel.Result result){
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        Boolean isWithRect = call.argument("isWithRect");
        if(isWithRect != null && isWithRect){
            ocrRectView.takePhotoCameraWithRect();
        }else{
            ocrRectView.takePhotoCamera();
        }
        result.success(true);
    }

    private void switchCamera(MethodChannel.Result result){
        if (ocrRectView == null) {
            ocrViewNotSet(result);
            return;
        }
        ocrRectView.switchCamera();
        result.success(true);
    }

    private boolean hasFlash() {
        return hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
    }

    private boolean hasSystemFeature(String feature) {
        return getActivity() != null && getActivity().getPackageManager()
                .hasSystemFeature(feature);
    }

    private void ocrViewNotSet(MethodChannel.Result result) {
        result.error("404", "No OcrRectView view found", null);
    }

    private boolean hasCameraPermission() {
        if (permissionGranted ||
                Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;
        return getActivity() != null &&
                getActivity().checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
    }

    private void checkAndRequestPermission(MethodChannel.Result result) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (getActivity() == null) {
                if (result != null) result.error("1", "no activity for check permission", null);
                return;
            }
            if (getActivity().checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                permissionGranted = true;
                channel.invokeMethod("onPermissionSet", true);
            } else {
                getActivity().requestPermissions(
                        new String[]{Manifest.permission.CAMERA},
                        Shared.CAMERA_REQUEST_ID);
            }
            if (result != null) result.success(true);
        } else {
            if (result != null)
                result.error("1", "cameraPermission Platform Version to low for camera permission check", null);
        }
    }

    private void init() {
        if (Shared.binding != null) {
            Shared.binding.addRequestPermissionsResultListener(this);
            Shared.binding.addActivityResultListener(this);
        }
        if (Shared.registrar != null) {
            Shared.registrar.addRequestPermissionsResultListener(this);
            Shared.registrar.addActivityResultListener(this);
        }
        if (getActivity() == null) {
            return;
        }
        getActivity().getApplication().registerActivityLifecycleCallbacks(mMyLifecycleCallbacks);
    }

    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        if(resultCode == Activity.RESULT_OK && requestCode == REQUEST_TAKE){
            Uri uri = data == null ? null : data.getData();
            if(uri != null){
                String path = FilePathUtils.getImagePath(getActivity(),uri);
                if(path == null || path.length() == 0) path = uri.getPath();
                HashMap<String, String> map = new HashMap<>();
                map.put("imgPath", path);
                callbackInfo(map);
            }
            return true;
        }
        return false;
    }

    private void callbackInfo(Object data){
        channel.invokeMethod("onOcrRecognize", data);
    }

    private class MyLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
        }

        @Override
        public void onActivityStarted(@NonNull Activity activity) {
        }

        @Override
        public void onActivityResumed(@NonNull Activity activity) {
            if (ocrRectView != null && !isPaused && hasCameraPermission()) {
                ocrRectView.resume();
            }
        }

        @Override
        public void onActivityPaused(@NonNull Activity activity) {
            if (ocrRectView != null && !isPaused && hasCameraPermission()) {
                ocrRectView.pause();
            }
        }

        @Override
        public void onActivityStopped(@NonNull Activity activity) {
        }

        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
        }

        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {
        }
    }

}
